# coding: utf8

import numpy as np

"""
Numpy模块提供了数据类型类dtype，各种NumPy数值类型都是numpy.dtype类型的实例。

NumPy支持比Python更多种类的数字类型，设置的原始类型与C中的原始类型紧密相关。
-------------------------------------------------------------------------------------------------
Numpy类型	    C类型	            描述
-------------------------------------------------------------------------------------------------
np.bool	        bool	            存储为字节的布尔值（True或False）
np.byte	        signed char	        平台定义
np.ubyte	    unsigned char	    平台定义
np.short	    short	            平台定义
np.ushort	    unsigned short	    平台定义
np.intc	        int	                平台定义
np.uintc	    unsigned int	    平台定义
np.int_	        long	            平台定义
np.uint	        unsigned long	    平台定义
np.longlong	    long long	        平台定义
np.ulonglong	unsigned long long	平台定义
np.half / 
np.float16		                    半精度浮点数：符号位，5位指数，10位尾数
np.single	    float	            平台定义的单精度浮点数：通常为符号位，8位指数，23位尾数
np.double	    double	            平台定义的双精度浮点数：通常为符号位，11位指数，52位尾数。
np.longdouble	long double	        平台定义的扩展精度浮点数
np.csingle	    float complex	    复数，由两个单精度浮点数（实部和虚部）表示
np.cdouble	double complex	        复数，由两个双精度浮点数（实部和虚部）表示。
np.clongdouble	long double complex	复数，由两个扩展精度浮点数（实部和虚部）表示。
-------------------------------------------------------------------------------------------------

由于许多数据类型依赖于具体平台定义，Numpy提供了带有固定大小的数据类型别名。
-------------------------------------------------------------------------------------------------
Numpy类型	    C类型	        描述
-------------------------------------------------------------------------------------------------
np.int8	        int8_t	        字节（-128到127）
np.int16	    int16_t	        整数（-32768至32767）
np.int32	    int32_t	        整数（-2147483648至2147483647）
np.int64	    int64_t	        整数（-9223372036854775808至9223372036854775807）
np.uint8	    uint8_t	        无符号整数（0到255）
np.uint16	    uint16_t	    无符号整数（0到65535）
np.uint32	    uint32_t	    无符号整数（0到4294967295）
np.uint64	    uint64_t	    无符号整数（0到18446744073709551615）
np.intp	        intptr_t	    用于索引的整数，通常与索引相同 ssize_t
np.uintp	    uintptr_t	    整数大到足以容纳指针
np.float16                      半精度浮点数：符号位，5位指数，10位尾数
np.float32	    float	        单精度浮点数：通常为符号位，8位指数，23位尾数
np.float64/
np.float_	    double	        双精度浮点数：1位符号位，11位指数，52位尾数。与float精度一致。
np.complex64	float complex	复数，由两个64位浮点数（实数和虚数组件）组成。与python复数complex精度一致。
np.complex128/
np.complex_	    double complex	由两个扩展精度浮点数（实部和虚部）
-------------------------------------------------------------------------------------------------

NumPy 有一些额外的数据类型，并通过一个字符引用数据类型，例如 i 代表整数，u 代表无符号整数等。
以下是 NumPy 中所有数据类型的列表以及用于表示它们的字符。
-------------------------------------------------------------------------------------------------
字符代码            对应类型
-------------------------------------------------------------------------------------------------
b（小写）           布尔型
i（小写）           有符号整型，使用'i1',  'i2', 'i4', 'i8' 对应 int8,  int16,  int32,  int64
u（小写）           无符号整型，使用'u1',  'u2', 'u4', 'u8' 对应 uint8,  uint16,  uint32,  uint64
f（小写）           浮点型，使用'f2', 'f4'/'f', 'f8'/'d'/'g' 对应 float16, float32, float64
c（小写）           复数，'c8', 'c16' 对应 complex64, complex128
m（小写）           timedelta64（时间间隔），存储数值本质上是int64
M（大写）           datetime64（日期时间）
O（大写）           Python 对象
S（大写）/a（小写）   byte字节串，只能包含ASCII码字符，S或a后数字表示字符串长度，超出部分将被截断，例如 S20、a10
U（大写）           Unicode字符串，U后数字表示字符串长度，超出部分将被截断，例如 U20
V（大写）           bytes数组，V后带数字表示数组长度，超出部分将被截断，不足则补零
-------------------------------------------------------------------------------------------------

Numpy的其他数据类型：
-------------------------------------------------------------------------------------------------
datetime64          日期时间类型      numpy1.7版本后增加 
timedelta           时间差类型

"""

def demo_base_dtype():
    # 浮点类型数据
    data1 = [[0, 1], [1.2, 2]]
    a = np.array(data1, dtype=np.float16)
    print(a, '\n', a.dtype)

    # 复数类型数组
    data2 = [1+2j, 23]
    b = np.array(data2, dtype=np.complex_)
    print(b, '\n', b.dtype)


def demo_complex_dtype():
    # 结构化数组: 构建复杂结构的元素，每个元素仍然结构相同，而可以按名称访问结构的每个部分
    # 有几种结构化数组赋值方式：（1）使用python元组；（2）标量值；（3）其他结构化数组。
    dtype01 = np.dtype('i8, f4, S3')
    print(dtype01.names)
    print(dtype01.fields)
    c1 = np.array([(10, 12.3, "abc"), (12, 21.22, "rsw")], dtype=dtype01)
    print(c1)
    print("c1[0]={}, c1[1]={}".format(c1[0], c1[1]))

    # 多层结构的结构化数组
    dtype02 = np.dtype([('x', 'f4'), ('y', np.float32), ('z', 'f4', (2,))])
    c2 = np.array([(11.2, 22.3, [1, 12])], dtype=dtype02)
    cs = "c2[0]={}, c2[0][2]={}, c2[0][2][0]={}".format(c2[0], c2[0][2], c2[0][2][0])
    print(
        ">>> dtype02 = np.dtype([('x', 'f4'), ('y', np.float32), ('z', 'f4', (2,))])\n"
        ">>> c2 = np.array([(11.2, 22.3, [1, 12])], dtype=dtype02)\n"
        f"{c2}\n"
        """c2[0]={}, c2[0][2]={}, c2[0][2][0]={}".format(c2[0], c2[0][2], c2[0][2][0])"""
        f"""{cs}"""
    )

    # 使用字典定义结构化数组
    dtype03 = np.dtype({'names': ['col1', 'col2'], 'formats': ['i4', 'f4']})
    print(
        ">>> np.dtype({'names': ['col1', 'col2'], 'formats': ['i4', 'f4']})\n"
        f"{dtype03}"
    )

    # 使用单字母类型
    x = np.zeros(2, dtype='i8, f4, ?, S1')
    print(
        ">>> np.zeros(2, dtype='i8, f4, ?, S1')\n"
        f"{x}\n"
        f">>> x.dtype\n"
        f"{x.dtype}"
    )

    student_type = np.dtype([('name', 'U10'), ('age', 'M8[D]')])
    student_data = np.array([('zhang-li', np.datetime64('2001-01-02'))], dtype=student_type)
    print(
        ">>> student_type = np.dtype([('name', 'S4'), ('age', 'M8[D]')])\n"
        f"{student_type}\n"
        ">>> student_data = np.array([('Zhang-li', np.datetime64('2001-01-02'))], dtype=student_type)\n"
        # f"{student_data}"
    )


def demo_ndarray_attributes():
    a = np.eye(2, 3)
    print(
        ">>> a = np.eye(2,3)\n"
        ">>> a.T\n"
        f"{a.T}\n"
        f">>> a.size\n"
        f"{a.size}\n"
        f">>> [x for x in a.flat]\n"
        f"{[x for x in a.flat]}"
    )

def task():
    # 数据记录需要使用元组，不能使用列表
    data = [('张力', 15, 182.5), ('李明', 25, 180)]
    stu_dtype = np.dtype([('name', 'U10'), ('age', 'u1'), ('height', 'f2')])
    stu_array = np.array(data, dtype=stu_dtype)
    print(stu_array)


def expand():
    import faker
    fk = faker.Faker('zh_cn')
    data = []
    for j in range(5):
        d = (fk.name(),
             fk.random.uniform(160, 200),
             fk.random.uniform(50, 80),
             fk.random.choices([np.datetime64(d*10+360*30, 'D') for d in range(100)])[0])
        print("{}, {:.1f}, {:.1f}, {}".format(*d))
        data.append(d)
    print(data)
    stu_type = np.dtype([('name', 'U20'), ('weight', 'f2'), ('height', 'f2'), ('birthday', 'M8[D]')])
    print(stu_type)
    stu_data = np.array(data, dtype=stu_type)
    print(stu_data)


if __name__ == '__main__':
    # demo_complex_dtype()
    # demo_ndarray_attributes()
    # task()
    expand()